package neatlogic.module.change.stephandler.component;

import neatlogic.framework.asynchronization.threadlocal.TenantContext;
import neatlogic.framework.asynchronization.threadlocal.UserContext;
import neatlogic.framework.common.constvalue.GroupSearch;
import neatlogic.framework.process.constvalue.*;
import neatlogic.framework.process.dto.ProcessTaskStepVo;
import neatlogic.framework.process.dto.ProcessTaskStepWorkerVo;
import neatlogic.framework.process.exception.processtask.ProcessTaskException;
import neatlogic.framework.process.exception.process.ProcessStepUtilHandlerNotFoundException;
import neatlogic.framework.process.stephandler.core.IProcessStepInternalHandler;
import neatlogic.framework.process.stephandler.core.ProcessStepHandlerBase;
import neatlogic.framework.process.stephandler.core.ProcessStepInternalHandlerFactory;
import neatlogic.framework.scheduler.core.IJob;
import neatlogic.framework.scheduler.core.SchedulerManager;
import neatlogic.framework.scheduler.dto.JobObject;
import neatlogic.framework.scheduler.exception.ScheduleHandlerNotFoundException;
import neatlogic.framework.util.TimeUtil;
import neatlogic.framework.change.constvalue.ChangeAuditType;
import neatlogic.framework.change.constvalue.ChangeOperationType;
import neatlogic.framework.change.constvalue.ChangeProcessStepHandlerType;
import neatlogic.framework.change.constvalue.ChangeStatus;
import neatlogic.module.change.dao.mapper.ChangeMapper;
import neatlogic.framework.change.dto.ChangeAutoStartVo;
import neatlogic.framework.change.dto.ChangeVo;
import neatlogic.framework.change.dto.ProcessTaskStepChangeVo;
import neatlogic.framework.change.exception.ChangeHandleHasNotStartedException;
import neatlogic.framework.change.exception.ChangeNoPermissionException;
import neatlogic.framework.change.exception.ChangeNotFoundException;
import neatlogic.framework.change.exception.ChangeTransferException;
import neatlogic.module.change.schedule.plugin.ChangeAutoStartJob;
import neatlogic.module.change.service.ChangeService;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONPath;
import com.google.common.base.Objects;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Set;

@Service
public class ChangeHandleProcessComponent extends ProcessStepHandlerBase {

    private static Logger logger = LoggerFactory.getLogger(ChangeHandleProcessComponent.class);

    @Autowired
    private ChangeMapper changeMapper;

    @Autowired
    private ChangeService changeService;

    @Override
    public String getHandler() {
        return ChangeProcessStepHandlerType.CHANGEHANDLE.getHandler();
    }

    @SuppressWarnings("serial")
    @Override
    public JSONObject getChartConfig() {
        return new JSONObject() {
            {
                this.put("icon", "tsfont-changing");
                this.put("shape", "L-rectangle:R-rectangle");
                this.put("width", 68);
                this.put("height", 40);
            }
        };
    }

    @Override
    public String getType() {
        return ChangeProcessStepHandlerType.CHANGEHANDLE.getType();
    }

    @Override
    public ProcessStepMode getMode() {
        return ProcessStepMode.MT;
    }

    @Override
    public String getName() {
        return ChangeProcessStepHandlerType.CHANGEHANDLE.getName();
    }

    @Override
    public int getSort() {
        return 7;
    }

    @Override
    public boolean isAsync() {
        return false;
    }

    @Override
    public Boolean isAllowStart() {
        return false;
    }

    @Override
    protected int myActive(ProcessTaskStepVo currentProcessTaskStepVo) throws ProcessTaskException {
        try {
            Long changeId = changeMapper.getChangeIdByProcessTaskStepId(currentProcessTaskStepVo.getId());
            if (changeId != null) {
                ChangeVo changeVo = changeMapper.getChangeById(changeId);
                if (changeVo != null) {
                    /** 如果设置了自动开始变更 **/
                    if (Objects.equal(changeVo.getAutoStart(), 1)) {
                        try {
                            Date planStartTime = new SimpleDateFormat(TimeUtil.YYYY_MM_DD_HH_MM).parse(changeVo.getPlanStartTime());
                            if (planStartTime.after(new Date())) {
                                /** 如果还没到计划开始时间，则启动定时器 **/
                                IJob jobHandler = SchedulerManager.getHandler(ChangeAutoStartJob.class.getName());
                                if (jobHandler == null) {
                                    throw new ScheduleHandlerNotFoundException(ChangeAutoStartJob.class.getName());
                                }
                                ChangeAutoStartVo changeAutoStartVo = new ChangeAutoStartVo(changeId, planStartTime);
                                changeMapper.insertChangeAutoStart(changeAutoStartVo);
                                JobObject.Builder jobObjectBuilder = new JobObject
                                        .Builder(changeId.toString(), jobHandler.getGroupName(), jobHandler.getClassName(), TenantContext.get().getTenantUuid());
                                JobObject jobObject = jobObjectBuilder.build();
                                jobHandler.reloadJob(jobObject);
                            } else {
                                /** 如果过了计划开始时间，则开始变更 **/
                                String source = currentProcessTaskStepVo.getParamObj().getString("source");
                                changeService.startChangeById(changeId, source);
                            }
                        } catch (ParseException e) {
                            logger.error(e.getMessage(), e);
                        }
                    }
                }
            }
            return 0;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new ProcessTaskException(e.getMessage());
        }
    }

    @Override
    protected int myAssign(ProcessTaskStepVo currentProcessTaskStepVo, Set<ProcessTaskStepWorkerVo> workerSet) throws ProcessTaskException {
        try {
            /** 因为回退到变更创建后，可以修改变更经理，所以重新流转到变更处理时，处理人是可以改变的 **/
            workerSet.clear();
            /** 分配处理人 **/
            ProcessTaskStepVo processTaskStepVo = processTaskMapper.getProcessTaskStepBaseInfoById(currentProcessTaskStepVo.getId());
            String stepConfig = selectContentByHashMapper.getProcessTaskStepConfigByHash(processTaskStepVo.getConfigHash());
            if (StringUtils.isNotBlank(stepConfig)) {
                String linkedChange = (String) JSONPath.read(stepConfig, "linkedChange");
                if (StringUtils.isNotBlank(linkedChange)) {
                    ProcessTaskStepVo changeCreateStepVo = processTaskMapper.getProcessTaskStepBaseInfoByProcessTaskIdAndProcessStepUuid(currentProcessTaskStepVo.getProcessTaskId(), linkedChange);
                    if (changeCreateStepVo != null) {
                        Long changeId = changeMapper.getChangeIdByProcessTaskStepId(changeCreateStepVo.getId());
                        if (changeId != null) {
                            ChangeVo changeVo = changeMapper.getChangeById(changeId);
                            if (changeVo == null) {
                                throw new ChangeNotFoundException(changeId);
                            }
                            String userUuid = changeMapper.getChangeUserByChangeId(changeId);
                            if (StringUtils.isNotBlank(userUuid)) {
                                workerSet.add(new ProcessTaskStepWorkerVo(currentProcessTaskStepVo.getProcessTaskId(), currentProcessTaskStepVo.getId(), GroupSearch.USER.getValue(), userUuid, ProcessUserType.MAJOR.getValue()));
                            }
                            /** 插入变更处理节点与变更的关系数据 **/
                            ProcessTaskStepChangeVo processTaskStepChangeVo = new ProcessTaskStepChangeVo();
                            processTaskStepChangeVo.setProcessTaskId(currentProcessTaskStepVo.getProcessTaskId());
                            processTaskStepChangeVo.setProcessTaskStepId(currentProcessTaskStepVo.getId());
                            processTaskStepChangeVo.setChangeId(changeId);
                            changeMapper.insertIgnoreProcessTaskStepChangeHandle(processTaskStepChangeVo);
                        }
                    }
                }
            }

            return 1;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new ProcessTaskException(e.getMessage());
        }
    }

    @Override
    protected int myHang(ProcessTaskStepVo currentProcessTaskStepVo) {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    protected int myHandle(ProcessTaskStepVo currentProcessTaskStepVo) throws ProcessTaskException {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    protected int myStart(ProcessTaskStepVo currentProcessTaskStepVo) throws ProcessTaskException {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    protected int myComplete(ProcessTaskStepVo currentProcessTaskStepVo) throws ProcessTaskException {
        try {
            Long changeId = changeMapper.getChangeIdByProcessTaskStepId(currentProcessTaskStepVo.getId());
            if (changeId != null) {
                JSONObject paramObj = currentProcessTaskStepVo.getParamObj();
                String action = paramObj.getString("action");
                if (ProcessTaskOperationType.STEP_COMPLETE.getValue().equals(action)) {
//                if(changeMapper.checkChangeIsExists(changeId) == 0) {
//                    throw new ChangeNotFoundException(changeId);
//                }
                    /** 获取当前变更锁 **/
                    changeMapper.getChangeLockById(changeId);
                    String changeAction = paramObj.getString("changeAction");
                    ChangeVo changeVo = changeService.getChangeById(changeId);
                    if (!changeService.isCompletableChange(changeVo, UserContext.get().getUserUuid(true))) {
                        throw new ChangeNoPermissionException(ChangeOperationType.getText(changeAction));
                    }
                    /** 完成变更时，将变更状态设置为“已成功”或“已失败” **/
                    if (ChangeOperationType.SUCCEEDCHANGE.getValue().equals(changeAction)) {
                        changeVo.setStatus(ChangeStatus.SUCCEED.getValue());
                    } else {
                        changeVo.setStatus(ChangeStatus.FAILED.getValue());
                    }
                    changeMapper.updateChangeStatus(changeVo);

                    /** 完成变更时，触发更新processtask_step_worker和processtask_step_user数据 **/
                    ProcessTaskStepChangeVo processTaskStepChangeVo = changeMapper.getProcessTaskStepChangeHandleByChangeId(changeId);
                    if (processTaskStepChangeVo == null) {
                        throw new ChangeHandleHasNotStartedException();
                    }
                    IProcessStepInternalHandler processStepUtilHandler = ProcessStepInternalHandlerFactory.getHandler(ChangeProcessStepHandlerType.CHANGEHANDLE.getHandler());
                    if (processStepUtilHandler == null) {
                        throw new ProcessStepUtilHandlerNotFoundException(ChangeProcessStepHandlerType.CHANGEHANDLE.getHandler());
                    }
                    processStepUtilHandler.updateProcessTaskStepUserAndWorker(processTaskStepChangeVo.getProcessTaskId(), processTaskStepChangeVo.getProcessTaskStepId());
                } else {
                    ChangeAutoStartVo changeAutoStartVo = changeMapper.getChangeAutoStartByChangeId(changeId);
                    if (changeAutoStartVo != null) {
                        changeMapper.deleteChangeAutoStartByChangeId(changeId);
//                    schedulerManager.unloadJob(jobObject);
                    }
                }
            }

            return 1;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new ProcessTaskException(e.getMessage());
        }
    }

    @Override
    protected int myCompleteAudit(ProcessTaskStepVo currentProcessTaskStepVo) {
        JSONObject paramObj = currentProcessTaskStepVo.getParamObj();
        if (StringUtils.isNotBlank(currentProcessTaskStepVo.getError())) {
            paramObj.put(ProcessTaskAuditDetailType.CAUSE.getParamName(), currentProcessTaskStepVo.getError());
        }
        /** 处理历史记录 **/
        String action = paramObj.getString("action");
        if (ProcessTaskOperationType.STEP_COMPLETE.getValue().equals(action)) {
            String changeAction = paramObj.getString("changeAction");
            IProcessStepHandlerUtil.audit(currentProcessTaskStepVo, ChangeAuditType.getChangeAuditType(changeAction));
        } else {
            IProcessStepHandlerUtil.audit(currentProcessTaskStepVo, ProcessTaskAuditType.getProcessTaskAuditType(action));
        }
        return 1;
    }

    @Override
    protected int myReapproval(ProcessTaskStepVo currentProcessTaskStepVo) throws ProcessTaskException {
        return 0;
    }

    @Override
    protected int myReapprovalAudit(ProcessTaskStepVo currentProcessTaskStepVo) {
        return 0;
    }

    @Override
    protected int myRetreat(ProcessTaskStepVo currentProcessTaskStepVo) throws ProcessTaskException {
        return 1;
    }

    @Override
    protected int myAbort(ProcessTaskStepVo currentProcessTaskStepVo) {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    protected int myRecover(ProcessTaskStepVo currentProcessTaskStepVo) {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    protected int myTransfer(ProcessTaskStepVo currentProcessTaskStepVo, List<ProcessTaskStepWorkerVo> workerList) throws ProcessTaskException {
        try {
            if (workerList.size() > 1) {
                throw new ChangeTransferException();
            }
            String userUuid = null;
            if (GroupSearch.USER.getValue().equals(workerList.get(0).getType())) {
                userUuid = workerList.get(0).getUuid();
            } else {
                throw new ChangeTransferException();
            }
            Long changeId = changeMapper.getChangeIdByProcessTaskStepId(currentProcessTaskStepVo.getId());
            if (changeId != null) {
                ChangeVo changeVo = changeMapper.getChangeById(changeId);
                if (changeVo == null) {
                    throw new ChangeNotFoundException(changeId);
                }
                changeMapper.deleteChangeUserByChangeId(changeId);
                changeMapper.insertChangeUser(changeId, userUuid);
            }
            return 1;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new ProcessTaskException(e.getMessage());
        }
    }

    @Override
    protected int myBack(ProcessTaskStepVo currentProcessTaskStepVo) throws ProcessTaskException {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    protected int mySaveDraft(ProcessTaskStepVo currentProcessTaskStepVo) throws ProcessTaskException {
        return 0;
    }

    @Override
    protected int myStartProcess(ProcessTaskStepVo currentProcessTaskStepVo) throws ProcessTaskException {
        return 0;
    }

    @Override
    protected Set<Long> myGetNext(ProcessTaskStepVo currentProcessTaskStepVo, List<Long> nextStepIdList, Long nextStepId) throws ProcessTaskException {
        return defaultGetNext(nextStepIdList, nextStepId);
    }

    @Override
    protected int myRedo(ProcessTaskStepVo currentProcessTaskStepVo) {
        return 0;
    }

    @Override
    protected int myPause(ProcessTaskStepVo currentProcessTaskStepVo) throws ProcessTaskException {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    protected List<ProcessTaskStepWorkerVo> myMinorWorkerList(ProcessTaskStepVo taskStepVo) {
        return changeMapper.getChangeStepWorkerList(taskStepVo.getId());
    }

    @Override
    protected String myMinorName() {
        return "变更步骤";
    }
}
